/*
 * @(#)AbstractMemberWriter.java 1.69 04/05/18
 * 
 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. SUN
 * PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package net.sf.odinms.exttools.doclet.writers;

import java.lang.reflect.Modifier;
import java.util.Iterator;
import java.util.List;
import com.sun.javadoc.*;
import com.sun.tools.doclets.internal.toolkit.taglets.DeprecatedTaglet;
import com.sun.tools.doclets.internal.toolkit.util.Util;
import com.sun.tools.doclets.internal.toolkit.util.VisibleMemberMap;
import net.sf.odinms.exttools.doclet.Config;

/**
 * The base class for member writers.
 * 
 * @author Robert Field
 * @author Atul M Dambalkar
 * @author Jamie Ho (Re-write)
 * 
 * @deprecated Legacy code from Standard Doclet.
 */
public abstract class AbstractMemberWriter {
	
	protected boolean printedSummaryHeader = false;
	protected final SubWriterHolderWriter writer;
	protected final ClassDoc classdoc;
	public final boolean nodepr;
	
	public AbstractMemberWriter(SubWriterHolderWriter writer, ClassDoc classdoc) {
		this.writer = writer;
		this.nodepr = configuration().nodeprecated;
		this.classdoc = classdoc;
	}
	
	public AbstractMemberWriter(SubWriterHolderWriter writer) {
		this(writer, null);
	}
	
	/** * abstracts ** */
	
	public abstract void printSummaryLabel(ClassDoc cd);
	
	public abstract void printInheritedSummaryLabel(ClassDoc cd);
	
	public abstract void printSummaryAnchor(ClassDoc cd);
	
	public abstract void printInheritedSummaryAnchor(ClassDoc cd);
	
	protected abstract void printSummaryType(ProgramElementDoc member);
	
	protected void writeSummaryLink(ClassDoc cd, ProgramElementDoc member) {
		writeSummaryLink(LinkInfoImpl.CONTEXT_MEMBER, cd, member);
	}
	
	protected abstract void writeSummaryLink(int context, ClassDoc cd,
			ProgramElementDoc member);
	
	protected abstract void writeInheritedSummaryLink(ClassDoc cd,
			ProgramElementDoc member);
	
	protected abstract void writeDeprecatedLink(ProgramElementDoc member);
	
	protected abstract void printNavSummaryLink(ClassDoc cd, boolean link);
	
	protected abstract void printNavDetailLink(boolean link);
	
	/** * ** */
	
	protected void print(String str) {
		writer.print(str);
		writer.displayLength += str.length();
	}
	
	protected void print(char ch) {
		writer.print(ch);
		writer.displayLength++;
	}
	
	protected void bold(String str) {
		writer.bold(str);
		writer.displayLength += str.length();
	}
	
	/**
	 * Return a string describing the access modifier flags. Don't include
	 * native or synchronized.
	 * 
	 * The modifier names are returned in canonical order, as specified by
	 * <em>The Java Language Specification</em>.
	 */
	protected String modifierString(MemberDoc member) {
		int ms = member.modifierSpecifier();
		int no = Modifier.NATIVE | Modifier.SYNCHRONIZED;
		return Modifier.toString(ms & ~no);
	}
	
	protected String typeString(MemberDoc member) {
		String type = "";
		if (member instanceof MethodDoc) {
			type = ((MethodDoc) member).returnType().toString();
		} else if (member instanceof FieldDoc) {
			type = ((FieldDoc) member).type().toString();
		}
		return type;
	}
	
	protected void printModifiers(MemberDoc member) {
		String mod = modifierString(member);
		// According to JLS, we should not be showing public modifier for
		// interface methods.
		if ((member.isField() || member.isMethod())
				&& writer instanceof ClassWriterImpl
				&& ((ClassWriterImpl) writer).getClassDoc().isInterface()) {
			mod = Util.replaceText(mod, "public", "").trim();
		}
		if (mod.length() > 0) {
			print(mod);
			print(' ');
		}
	}
	
	protected String makeSpace(int len) {
		if (len <= 0) {
			return "";
		}
		StringBuffer sb = new StringBuffer(len);
		for (int i = 0; i < len; i++) {
			sb.append(' ');
		}
		return sb.toString();
	}
	
	/**
	 * Print 'static' if static and type link.
	 */
	protected void printStaticAndType(boolean isStatic, Type type) {
		writer.printTypeSummaryHeader();
		if (isStatic) {
			print("static");
		}
		writer.space();
		if (type != null) {
			writer.printLink(new LinkInfoImpl(LinkInfoImpl.CONTEXT_MEMBER, type));
		}
		writer.printTypeSummaryFooter();
	}
	
	/**
	 * Print the modifier and type for the member in the member summary.
	 * 
	 * @param member the member to print the type for.
	 * @param type the type to print.
	 */
	protected void printModifierAndType(ProgramElementDoc member, Type type) {
		writer.printTypeSummaryHeader();
		printModifier(member);
		if (type == null) {
			writer.space();
			if (member.isClass()) {
				print("class");
			} else {
				print("interface");
			}
		} else {
			if (member instanceof ExecutableMemberDoc
					&& ((ExecutableMemberDoc) member).typeParameters().length > 0) {
				// Code to avoid ugly wrapping in member summary table.
				writer.table(0, 0, 0);
				writer.trAlignVAlign("right", "");
				writer.tdNowrap();
				writer.font("-1");
				writer.code();
				int displayLength = ((AbstractExecutableMemberWriter) this).writeTypeParameters((ExecutableMemberDoc) member);
				if (displayLength > 10) {
					writer.br();
				}
				writer.printLink(new LinkInfoImpl(
						LinkInfoImpl.CONTEXT_SUMMARY_RETURN_TYPE, type));
				writer.codeEnd();
				writer.fontEnd();
				writer.tdEnd();
				writer.trEnd();
				writer.tableEnd();
			} else {
				writer.space();
				writer.printLink(new LinkInfoImpl(
						LinkInfoImpl.CONTEXT_SUMMARY_RETURN_TYPE, type));
			}
			
		}
		writer.printTypeSummaryFooter();
	}
	
	private void printModifier(ProgramElementDoc member) {
		if (member.isProtected()) {
			print("protected ");
		} else if (member.isPrivate()) {
			print("private ");
		} else if (!member.isPublic()) { // Package private
			writer.printText("doclet.Package_private");
			print(" ");
		}
		if (member.isMethod() && ((MethodDoc) member).isAbstract()) {
			print("abstract ");
		}
		if (member.isStatic()) {
			print("static");
		}
	}
	
	protected void printComment(ProgramElementDoc member) {
		if (member.inlineTags().length > 0) {
			writer.dd();
			writer.printInlineComment(member);
		}
	}
	
	protected String name(ProgramElementDoc member) {
		return member.name();
	}
	
	protected void printHead(MemberDoc member) {
		writer.h3();
		writer.print(member.name());
		writer.h3End();
	}
	
	protected void printFullComment(ProgramElementDoc member) {
		if (configuration().nocomment) {
			return;
		}
		writer.dl();
		print(((TagletOutputImpl) (new DeprecatedTaglet()).getTagletOutput(
				member, writer.getTagletWriterInstance(false))).toString());
		printCommentAndTags(member);
		writer.dlEnd();
	}
	
	protected void printCommentAndTags(ProgramElementDoc member) {
		printComment(member);
		writer.printTags(member);
	}
	
	/**
	 * Forward to containing writer
	 */
	public void printSummaryHeader(ClassDoc cd) {
		printedSummaryHeader = true;
		writer.printSummaryHeader(this, cd);
	}
	
	/**
	 * Forward to containing writer
	 */
	public void printInheritedSummaryHeader(ClassDoc cd) {
		writer.printInheritedSummaryHeader(this, cd);
	}
	
	/**
	 * Forward to containing writer
	 */
	public void printInheritedSummaryFooter(ClassDoc cd) {
		writer.printInheritedSummaryFooter(this, cd);
	}
	
	/**
	 * Forward to containing writer
	 */
	public void printSummaryFooter(ClassDoc cd) {
		writer.printSummaryFooter(this, cd);
	}
	
	/**
	 * Return true if the given <code>ProgramElement</code> is inherited by
	 * the class that is being documented.
	 * 
	 * @param ped The code>ProgramElement</code> being checked. return true if
	 *        the code>ProgramElement</code> is being inherited and false
	 *        otherwise.
	 */
	protected boolean isInherited(ProgramElementDoc ped) {
		if (ped.isPrivate()
				|| (ped.isPackagePrivate() && !ped.containingPackage().equals(
						classdoc.containingPackage()))) {
			return false;
		}
		return true;
	}
	
	/**
	 * Generate the code for listing the deprecated APIs. Create the table
	 * format for listing the API. Call methods from the sub-class to complete
	 * the generation.
	 */
	protected void printDeprecatedAPI(List deprmembers, String headingKey) {
		if (deprmembers.size() > 0) {
			writer.tableIndexSummary();
			writer.tableHeaderStart("#CCCCFF");
			writer.boldText(headingKey);
			writer.tableHeaderEnd();
			for (int i = 0; i < deprmembers.size(); i++) {
				ProgramElementDoc member = (ProgramElementDoc) deprmembers.get(i);
				writer.trBgcolorStyle("white", "TableRowColor");
				writer.summaryRow(0);
				writeDeprecatedLink(member);
				writer.br();
				writer.printNbsps();
				if (member.tags("deprecated").length > 0)
					writer.printInlineDeprecatedComment(member,
							member.tags("deprecated")[0]);
				writer.space();
				writer.summaryRowEnd();
				writer.trEnd();
			}
			writer.tableEnd();
			writer.space();
			writer.p();
		}
	}
	
	/**
	 * Print use info.
	 */
	protected void printUseInfo(Object mems, String heading) {
		if (mems == null) {
			return;
		}
		List members = (List) mems;
		if (members.size() > 0) {
			writer.tableIndexSummary();
			writer.tableUseInfoHeaderStart("#CCCCFF");
			writer.print(heading);
			writer.tableHeaderEnd();
			for (Iterator it = members.iterator(); it.hasNext();) {
				ProgramElementDoc pgmdoc = (ProgramElementDoc) it.next();
				ClassDoc cd = pgmdoc.containingClass();
				
				writer.printSummaryLinkType(this, pgmdoc);
				if (cd != null && !(pgmdoc instanceof ConstructorDoc)
						&& !(pgmdoc instanceof ClassDoc)) {
					// Add class context
					writer.bold(cd.name() + ".");
				}
				writeSummaryLink(pgmdoc instanceof ClassDoc
						? LinkInfoImpl.CONTEXT_CLASS_USE
						: LinkInfoImpl.CONTEXT_MEMBER, cd, pgmdoc);
				writer.printSummaryLinkComment(this, pgmdoc);
			}
			writer.tableEnd();
			writer.space();
			writer.p();
		}
	}
	
	protected void navDetailLink(List members) {
		printNavDetailLink(members.size() > 0 ? true : false);
	}
	
	protected void navSummaryLink(List members,
			VisibleMemberMap visibleMemberMap) {
		if (members.size() > 0) {
			printNavSummaryLink(null, true);
			return;
		} else {
			ClassDoc icd = classdoc.superclass();
			while (icd != null) {
				List inhmembers = visibleMemberMap.getMembersFor(icd);
				if (inhmembers.size() > 0) {
					printNavSummaryLink(icd, true);
					return;
				}
				icd = icd.superclass();
			}
		}
		printNavSummaryLink(null, false);
	}
	
	protected void serialWarning(SourcePosition pos, String key, String a1,
			String a2) {
		if (configuration().serialwarn) {
			Config.getInstance().getDocletSpecificMsg().warning(pos, key,
					a1, a2);
		}
	}
	
	public ProgramElementDoc[] eligibleMembers(ProgramElementDoc[] members) {
		return nodepr ? Util.excludeDeprecatedMembers(members) : members;
	}
	
	public Config configuration() {
		return writer.configuration;
	}
	
	public void writeMemberSummary(ClassDoc classDoc, ProgramElementDoc member,
			Tag[] firstSentenceTags, boolean isFirst, boolean isLast) {
		writer.printSummaryLinkType(this, member);
		writeSummaryLink(classDoc, member);
		writer.printSummaryLinkComment(this, member, firstSentenceTags);
	}
}
